﻿#pragma execution_character_set("utf-8")
#include "fileworker.h"
#include "datacenter.h"
#include "filepathmanager.h"
#include "logger.h"
#include <QSharedPointer>
#include <QCoreApplication>
#include <QWaitCondition>
#include <QMutex>
#include <QQueue>
#include <QDebug>
#include <QThread>
#include <QDateTime>
#include <QTextStream>
#include <QFileInfo>
#include <QFile>
#include <QDir>


typedef QSharedPointer<QFile> QFilePtr;

class FileWorkerPrivate : public QThread
{
    Q_OBJECT
public:
    void start(const QString *arg = Q_NULLPTR);
    void stop();

signals:
    void dataFileReady(const QString &path);

private slots:
    void dataReady(const VdsMeasureDataPtr data);

protected:
    void run();

private:
    static QString buildFilePath(const QString &suffix = "");
    static QFilePtr openFile(const QString &path);
    static void closeFile(QFilePtr &file);

private:
    QWaitCondition m_condition;
    QMutex m_mutex;
    volatile bool m_stop;
    QString m_dataFilePath;
    QQueue<VdsMeasureDataPtr> m_dataQueue;
};

FileWorker::FileWorker() : IComponent("FileWorker"), d(new FileWorkerPrivate)
{
}

FileWorker::~FileWorker()
{
    stop();
    d->deleteLater();
}

void FileWorker::start(const QString *arg)
{
    d->stop();
    d->start(arg);
}

void FileWorker::stop()
{
    d->stop();
}

void FileWorkerPrivate::dataReady(const VdsMeasureDataPtr data)
{
    QMutexLocker locker(&m_mutex);
    m_dataQueue.enqueue(data);
    m_condition.wakeAll();
}

QString FileWorkerPrivate::buildFilePath(const QString &suffix)
{
    QDateTime dt = QDateTime::currentDateTime();
    QString date = dt.date().toString("yyyy-MM-dd");
    QString time = dt.time().toString("hh-mm-ss-zzz");
    QString dataDir = FilePathManager::instance()->chartDir();
    return QString("%1/%2/{%3}-%4").arg(dataDir).arg(date).arg(time).arg(suffix);
}

QFilePtr FileWorkerPrivate::openFile(const QString &path)
{
    QFileInfo fileInfo(path);
    QDir dir(fileInfo.absoluteDir());
    if (!dir.mkpath(fileInfo.path()))
    {
        sysError("error: cannot create directory: %s", fileInfo.path().toStdString().data());
        return Q_NULLPTR;
    }

    QFilePtr file = QFilePtr(new QFile(path));
    if (!file->open(QFile::WriteOnly | QFile::Truncate))
    {
        sysError("error: cannot open file: %s", path.toStdString().data());
        return Q_NULLPTR;
    }

    return file;
}

void FileWorkerPrivate::closeFile(QFilePtr &file)
{
    if (!file.isNull())
    {
        file->flush();
        file->close();
        file.clear();
    }
}

void FileWorkerPrivate::start(const QString *arg)
{
    if (m_stop)
    {
        m_dataQueue.clear();
        connect(DataCenter::instance(), &DataCenter::dataReady, this, &FileWorkerPrivate::dataReady);
        connect(this, &FileWorkerPrivate::dataFileReady, DataCenter::instance(), &DataCenter::dataFileReady);

        m_dataFilePath = (arg != Q_NULLPTR) ? *arg : buildFilePath() + "data.txt";
        m_stop = false;
        QThread::start();
    }
}

void FileWorkerPrivate::stop()
{
    if (!m_stop)
    {
        disconnect(DataCenter::instance(), &DataCenter::dataReady, this, &FileWorkerPrivate::dataReady);

        m_mutex.lock();
        m_stop = true;
        m_condition.wakeAll();
        m_mutex.unlock();

        quit();
        wait();

        disconnect(this, &FileWorkerPrivate::dataFileReady, DataCenter::instance(), &DataCenter::dataFileReady);
    }
}

void FileWorkerPrivate::run()
{
    sysError("FileWorkerPrivate::run() start, thread ID: %d", QThread::currentThreadId());

    int length = 0;
    int lineIndex = 0;

    const QString &dataFilePath = m_dataFilePath;
    sysError("dataFilePath: %s", dataFilePath.toStdString().data());

    QFilePtr dataFile = openFile(dataFilePath);
    QTextStream dataStream(dataFile.data());
    dataStream.setCodec("utf-8");

    while (!m_stop || length > 0)
    {// 将队列中的数据写完后，再退出
        // 检查队列长度
        m_mutex.lock();
        length = m_dataQueue.length();

        if (!m_stop)
        {// 写完一次，等待下次触发
            m_condition.wait(&m_mutex);
            length = m_dataQueue.length();
        }

        m_mutex.unlock();

        if (length <= 0)
        {// 队列为空
            continue;
        }

        // 保存数据到文件
        for (int len = 0; len < length; ++len)
        {
            lineIndex++;
            QStringList dataStringList;
            const VdsMeasureDataPtr &measureData = m_dataQueue.head();
            dataStream << measureData->vrms << ",";

            m_mutex.lock();
            m_dataQueue.removeFirst();
            m_mutex.unlock();
        }
    }

    closeFile(dataFile);

    if (!lineIndex)
    {// 删除空文件
        sysError("remove empty file: %d", QFile::remove(dataFilePath));
    }

    emit dataFileReady((lineIndex > 0) ? m_dataFilePath : "");
    sysError("FileWorkerPrivate::run() stopped.");
}


#include "fileworker.moc"
